use crate::model::indicators::adx::ADXConfig;
use crate::model::indicators::adx::ADX;
use crate::model::indicators::aroon::AROONConfig;
use crate::model::indicators::aroon::AROON;
use crate::model::indicators::aso::ASOConfig;
use crate::model::indicators::aso::ASO;
use crate::model::indicators::boll::BOLLConfig;
use crate::model::indicators::boll::BOLL;
use crate::model::indicators::cci::CCIConfig;
use crate::model::indicators::cci::CCI;
use crate::model::indicators::cko::CKOConfig;
use crate::model::indicators::cko::CKO;
use crate::model::indicators::cks::CKSConfig;
use crate::model::indicators::cks::CKS;
use crate::model::indicators::cmf::CMFConfig;
use crate::model::indicators::cmf::CMF;
use crate::model::indicators::cmo::CMOConfig;
use crate::model::indicators::cmo::CMO;
use crate::model::indicators::cpc::CPCConfig;
use crate::model::indicators::cpc::CPC;
use crate::model::indicators::dcc::DCCConfig;
use crate::model::indicators::dcc::DCC;
use crate::model::indicators::dpo::DPOConfig;
use crate::model::indicators::dpo::DPO;
use crate::model::indicators::efi::EFIConfig;
use crate::model::indicators::efi::EFI;
use crate::model::indicators::eom::EOMConfig;
use crate::model::indicators::eom::EOM;
use crate::model::indicators::evl::EVLConfig;
use crate::model::indicators::evl::EVL;
use crate::model::indicators::ftf::FTFConfig;
use crate::model::indicators::ftf::FTF;
use crate::model::indicators::hma::HMAConfig;
use crate::model::indicators::hma::HMA;
use crate::model::indicators::ikc::IKCConfig;
use crate::model::indicators::ikc::IKC;
use crate::model::indicators::kama::KAMAConfig;
use crate::model::indicators::kama::KAMA;
use crate::model::indicators::kdj::KDJConfig;
use crate::model::indicators::kdj::KDJ;
use crate::model::indicators::knc::KNCConfig;
use crate::model::indicators::knc::KNC;
use crate::model::indicators::kst::KSTConfig;
use crate::model::indicators::kst::KST;
use crate::model::indicators::kvo::KVOConfig;
use crate::model::indicators::kvo::KVO;
use crate::model::indicators::macd::MACDConfig;
use crate::model::indicators::macd::MACD;
use crate::model::indicators::mfi::MFIConfig;
use crate::model::indicators::mfi::MFI;
use crate::model::indicators::mti::MTIConfig;
use crate::model::indicators::mti::MTI;
use crate::model::indicators::pcs::PCSConfig;
use crate::model::indicators::pcs::PCS;
use crate::model::indicators::prs::PRSConfig;
use crate::model::indicators::prs::PRS;
use crate::model::indicators::rsi::RSIConfig;
use crate::model::indicators::rsi::RSI;
use crate::model::indicators::rvi::RVIConfig;
use crate::model::indicators::rvi::RVI;
use crate::model::indicators::sar::SARConfig;
use crate::model::indicators::sar::SAR;
use crate::model::indicators::sei::SEIConfig;
use crate::model::indicators::sei::SEI;
use crate::model::indicators::tdsi::TDSIConfig;
use crate::model::indicators::tdsi::TDSI;
use crate::model::indicators::trix::TRIXConfig;
use crate::model::indicators::trix::TRIX;
use crate::model::indicators::trsi::TRSIConfig;
use crate::model::indicators::trsi::TRSI;
use crate::model::indicators::wcci::WCCIConfig;
use crate::model::indicators::wcci::WCCI;
use crate::model::indicators::Indicator;
use crate::model::kline::Kline;
use crate::model::FudaRecord;
use adx::Adx;
// use crate::model::Fund;
use anyhow::anyhow;
use anyhow::ensure;
use anyhow::Ok;
use anyhow::Result;
use aroon::Aroon;
use aso::Aso;
use boll::Boll;
use cci::Cci;
use chrono::Utc;
use cko::Cko;
use cks::Cks;
use cmf::Cmf;
use cmo::Cmo;
use cpc::Cpc;
use dcc::Dcc;
use dpo::Dpo;
use efi::Efi;
use eom::Eom;
use evl::Evl;
use ftf::Ftf;
use hma::Hma;
use ikc::Ikc;
use kama::Kama;
use kdj::Kdj;
use knc::Knc;
use kst::Kst;
use kvo::Kvo;
use macd::Macd;
use mfi::Mfi;
use mti::Mti;
use pcs::Pcs;
use prs::Prs;
use rsi::Rsi;
use rvi::Rvi;
use sar::Sar;
use sei::Sei;
use surrealdb::opt::PatchOp;
use tdsi::Tdsi;
use trix::Trix;
use trsi::Trsi;
use wcci::Wcci;

use super::FUDB;
use super::FUHLC;
use serde::Deserialize;
use serde::Serialize;
use surrealdb::sql::Thing;

pub mod adx;
pub mod aroon;
pub mod aso;
pub mod boll;
pub mod cci;
pub mod cko;
pub mod cks;
pub mod cmf;
pub mod cmo;
pub mod cpc;
pub mod dcc;
pub mod dpo;
pub mod efi;
pub mod eom;
pub mod evl;
pub mod ftf;
pub mod hma;
pub mod ikc;
pub mod kama;
pub mod kdj;
pub mod knc;
pub mod kst;
pub mod kvo;
pub mod macd;
pub mod mfi;
pub mod mti;
pub mod pcs;
pub mod prs;
pub mod rsi;
pub mod rvi;
pub mod sar;
pub mod sei;
pub mod tdsi;
pub mod trix;
pub mod trsi;
pub mod wcci;

#[derive(Debug, Serialize, Deserialize, Clone)]
struct KV3 {
    /// Kline Id
    pub id: Thing,

    /// computed adx value for the Kline of klid using kline.close
    pub adx: ADX,
    /// computed aroon value for the Kline of klid using kline.close
    pub aroon: AROON,
    /// computed aso value for the Kline of klid using kline.close
    pub aso: ASO,
    /// computed boll value for the Kline of klid using kline.close
    pub boll: BOLL,
    /// computed cci value for the Kline of klid using kline.close
    pub cci: CCI,

    /// computed cko value for the Kline of klid using kline.close
    pub cko: CKO,
    /// computed cks value for the Kline of klid using kline.close
    pub cks: CKS,
    /// computed cmf value for the Kline of klid using kline.close
    pub cmf: CMF,
    /// computed cmo value for the Kline of klid using kline.close
    pub cmo: CMO,
    /// computed cpc value for the Kline of klid using kline.close
    pub cpc: CPC,

    /// computed dcc value for the Kline of klid using kline.close
    pub dcc: DCC,
    /// computed dpo value for the Kline of klid using kline.close
    pub dpo: DPO,
    /// computed efi value for the Kline of klid using kline.close
    pub efi: EFI,
    /// computed eom value for the Kline of klid using kline.close
    pub eom: EOM,
    /// computed evl value for the Kline of klid using kline.close
    pub evl: EVL,

    /// computed ftf value for the Kline of klid using kline.close
    pub ftf: FTF,
    /// computed hma value for the Kline of klid using kline.close
    pub hma: HMA,
    /// computed ikc value for the Kline of klid using kline.close
    pub ikc: IKC,
    /// computed kama value for the Kline of klid using kline.close
    pub kama: KAMA,
    /// computed kdj value for the Kline of klid using kline.close
    pub kdj: KDJ,

    /// computed knc value for the Kline of klid using kline.close
    pub knc: KNC,
    /// computed kst value for the Kline of klid using kline.close
    pub kst: KST,
    /// computed kvo value for the Kline of klid using kline.close
    pub kvo: KVO,
    /// computed macd value for the Kline of klid using kline.close
    pub macd: MACD,
    /// computed mfi value for the Kline of klid using kline.close
    pub mfi: MFI,

    /// computed mti value for the Kline of klid using kline.close
    pub mti: MTI,
    /// computed pcs value for the Kline of klid using kline.close
    pub pcs: PCS,
    /// computed prs value for the Kline of klid using kline.close
    pub prs: PRS,
    /// computed rsi value for the Kline of klid using kline.close
    pub rsi: RSI,
    /// computed rvi value for the Kline of klid using kline.close
    pub rvi: RVI,

    /// computed sar value for the Kline of klid using kline.close
    pub sar: SAR,
    /// computed sei value for the Kline of klid using kline.close
    pub sei: SEI,
    /// computed tdsi value for the Kline of klid using kline.close
    pub tdsi: TDSI,
    /// computed trix value for the Kline of klid using kline.close
    pub trix: TRIX,
    /// computed trsi value for the Kline of klid using kline.close
    pub trsi: TRSI,
    /// computed wcci value for the Kline of klid using kline.close
    pub wcci: WCCI,
}

/// compute annd update all indicators' value for klines
pub async fn compute_n_update_all_indicators(klines: &Vec<Kline>) -> Result<u32> {
    ensure!(klines.len() > 0, "(inndicators::compute_n_update_all_indicators) klines is empty");

    let mut updates = 0u32;

    if let Some(fstk) = klines.first() {
        let start = Utc::now();
        let mut idc_values: Vec<KV3> = Vec::new();

        let mut adx = Adx::new(&ADXConfig::default(), fstk)?;
        let mut aroon = Aroon::new(&AROONConfig::default(), fstk)?;
        let mut aso = Aso::new(&ASOConfig::default(), fstk)?;
        let mut boll = Boll::new(&BOLLConfig::default(), fstk)?;
        let mut cci = Cci::new(&CCIConfig::default(), fstk)?;

        let mut cko = Cko::new(&CKOConfig::default(), fstk)?;
        let mut cks = Cks::new(&CKSConfig::default(), fstk)?;
        let mut cmf = Cmf::new(&CMFConfig::default(), fstk)?;
        let mut cmo = Cmo::new(&CMOConfig::default(), fstk)?;
        let mut cpc = Cpc::new(&CPCConfig::default(), fstk)?;

        let mut dcc = Dcc::new(&DCCConfig::default(), fstk)?;
        let mut dpo = Dpo::new(&DPOConfig::default(), fstk)?;
        let mut efi = Efi::new(&EFIConfig::default(), fstk)?;
        let mut eom = Eom::new(&EOMConfig::default(), fstk)?;
        let mut evl = Evl::new(&EVLConfig::default(), fstk)?;

        let mut ftf = Ftf::new(&FTFConfig::default(), fstk)?;
        let mut hma = Hma::new(&HMAConfig::default(), fstk)?;
        let mut ikc = Ikc::new(&IKCConfig::default(), fstk)?;
        let mut kama = Kama::new(&KAMAConfig::default(), fstk)?;
        let mut kdj = Kdj::new(&KDJConfig::default(), fstk)?;

        let mut knc = Knc::new(&KNCConfig::default(), fstk)?;
        let mut kst = Kst::new(&KSTConfig::default(), fstk)?;
        let mut kvo = Kvo::new(&KVOConfig::default(), fstk)?;
        let mut macd = Macd::new(&MACDConfig::default(), fstk)?;
        let mut mfi = Mfi::new(&MFIConfig::default(), fstk)?;

        let mut mti = Mti::new(&MTIConfig::default(), fstk)?;
        let mut pcs = Pcs::new(&PCSConfig::default(), fstk)?;
        let mut prs = Prs::new(&PRSConfig::default(), fstk)?;
        let mut rsi = Rsi::new(&RSIConfig::default(), fstk)?;
        let mut rvi = Rvi::new(&RVIConfig::default(), fstk)?;

        let mut sar = Sar::new(&SARConfig::default(), fstk)?;
        let mut sei = Sei::new(&SEIConfig::default(), fstk)?;
        let mut tdsi = Tdsi::new(&TDSIConfig::default(), fstk)?;
        let mut trix = Trix::new(&TRIXConfig::default(), fstk)?;
        let mut trsi = Trsi::new(&TRSIConfig::default(), fstk)?;

        let mut wcci = Wcci::new(&WCCIConfig::default(), fstk)?;

        for (i, kline) in klines.iter().enumerate() {
            if let Some(thing) = &kline.id {
                let adx_v = adx.next(&kline);
                let aso_v = aso.next(&kline);
                let aroon_v = aroon.next(&kline);
                let boll_v = boll.next(&kline);
                let cci_v = cci.next(&kline);

                let cko_v = cko.next(&kline);
                let cks_v = cks.next(&kline);
                let cmf_v = cmf.next(&kline);
                let cmo_v = cmo.next(&kline);
                let cpc_v = cpc.next(&kline);

                let dcc_v = dcc.next(&kline);
                let dpo_v = dpo.next(&kline);
                let efi_v = efi.next(&kline);
                let eom_v = eom.next(&kline);
                let evl_v = evl.next(&kline);

                let ftf_v = ftf.next(&kline);
                let hma_v = hma.next(&kline);
                let ikc_v = ikc.next(&kline);
                let kama_v = kama.next(&kline);
                let kdj_v = kdj.next(&kline);

                let knc_v = knc.next(&kline);
                let kst_v = kst.next(&kline);
                let kvo_v = kvo.next(&kline);
                let macd_v = macd.next(&kline);
                let mfi_v = mfi.next(&kline);

                let mti_v = mti.next(&kline);
                let pcs_v = pcs.next(&kline);
                let prs_v = prs.next(&kline);
                let rsi_v = rsi.next(&kline);
                let rvi_v = rvi.next(&kline);

                let sar_v = sar.next(&kline);
                let sei_v = sei.next(&kline);
                let tdsi_v = tdsi.next(&kline);
                let trix_v = trix.next(&kline);
                let trsi_v = trsi.next(&kline);

                let wcci_v = wcci.next(&kline);

                idc_values.push(KV3 {
                    id: thing.clone(),

                    adx: adx_v,
                    aroon: aroon_v,
                    aso: aso_v,
                    boll: boll_v,
                    cci: cci_v,

                    cko: cko_v,
                    cks: cks_v,
                    cmf: cmf_v,
                    cmo: cmo_v,
                    cpc: cpc_v,

                    dcc: dcc_v,
                    dpo: dpo_v,
                    efi: efi_v,
                    eom: eom_v,
                    evl: evl_v,

                    ftf: ftf_v,
                    hma: hma_v,
                    ikc: ikc_v,
                    kama: kama_v,
                    kdj: kdj_v,

                    knc: knc_v,
                    kst: kst_v,
                    kvo: kvo_v,
                    macd: macd_v,
                    mfi: mfi_v,

                    mti: mti_v,
                    pcs: pcs_v,
                    prs: prs_v,
                    rsi: rsi_v,
                    rvi: rvi_v,

                    sar: sar_v,
                    sei: sei_v,
                    tdsi: tdsi_v,
                    trix: trix_v,
                    trsi: trsi_v,

                    wcci: wcci_v,
                });
                updates += 1;
            }
        }

        let end1 = Utc::now();
        //TODO, use surrealdb Statement For loop
        let query = FUDB.query(
            r#"
                FOR $v IN $idc_values { UPDATE $v.id SET 
                adx = $v.adx, aroon = $v.aroon, aso = $v.aso, boll = $v.boll, cci = $v.cci, 
                cko = $v.cko, cks = $v.cks, cmf = $v.cmf, cmo = $v.cmo, cpc = $v.cpc, 
                dcc = $v.dcc, dpo = $v.dpo, efi = $v.efi, eom = $v.eom, evl = $v.evl, 
                ftf = $v.ftf, hma = $v.hma, ikc = $v.ikc, kama = $v.kama, kdj = $v.kdj, 
                knc = $v.knc, kst = $v.kst, kvo = $v.kvo, macd = $v.macd, mfi = $v.mfi, 
                mti = $v.mti, pcs = $v.pcs, prs = $v.prs, rsi = $v.rsi, rvi = $v.rvi, 
                sar = $v.sar, sei = $v.sei, tdsi = $v.tdsi, trix = $v.trix, trsi = $v.trsi,
                wcci = $v.wcci
                }
                "#
        ).bind(("idc_values", idc_values.clone()));

        // println!(
        //     "(indicators::compute_n_update_all_indicators) query={:?} \n\n idc_values[0]={:?}\n",
        //     query, idc_values[0]
        // );
        let _rs = query.await?;
        // println!("(indicators::compute_n_update_all_indicators) rs= {:?}", _rs);

        let end2 = Utc::now();

        println!(
            "(indicators::compute_n_update_all_indicators) spent time@computation={:?} time@UPDATE={:?} for klines.len={} \n",
            end1 - start,
            end2 - end1,
            klines.len()
        );
    }

    Ok(updates)
}

///
/// update or create a indicator record
///
/// @param indicator: indicator's basic information
///
pub async fn upsert(indicator: &Indicator) -> Result<Option<FudaRecord>> {
    let id = Indicator::id_from(&indicator.gk)?;

    let old_indicator: Option<Indicator> = FUDB.select(("indicator", id.as_str())).await?;

    let mut updated: Option<FudaRecord> = None;
    let mut to_update = false;
    let timestamp = FUHLC.new_timestamp().to_string();
    // Update a record with a specific ID
    let mut patch = FUDB.update(("indicator", &id)).patch(
        PatchOp::replace("/last_updated", timestamp)
    );

    match old_indicator {
        Some(Indicator { id: Some(t), .. }) => {
            updated = Some(FudaRecord { id: t });
        }
        _ => {
            patch = patch.patch(PatchOp::replace("/gk", &indicator.gk));
            patch = patch.patch(PatchOp::replace("/name", &indicator.name));
            patch = patch.patch(PatchOp::replace("/desc", &indicator.desc));
            patch = patch.patch(PatchOp::replace("/prompt", &indicator.prompt));
            to_update = true;
        }
    }

    if let Some(name) = &indicator.name {
        patch = patch.patch(PatchOp::replace("/name", name));
        to_update = true;
    }

    if let Some(desc) = &indicator.desc {
        patch = patch.patch(PatchOp::replace("/desc", desc));
        to_update = true;
    }

    if let Some(prompt) = &indicator.prompt {
        patch = patch.patch(PatchOp::replace("/prompt", prompt));
        to_update = true;
    }

    if to_update {
        updated = patch.await.map_err(|err| anyhow!(err))?;
    }

    Ok(updated)
}

///
/// delete indicator by it's id , e.g. SH.STK.600519
///
pub async fn delete(indicator_id: &str) -> Result<Indicator> {
    let rs: Option<Indicator> = FUDB.delete(("indicator", indicator_id)).await?;
    match rs {
        Some(indicator) => Ok(indicator),
        None => Err(anyhow!(format!("Failed to delete, Indicator not found for {}", indicator_id))),
    }
}

/// select indicators
///
/// type_: IndicatorType, indicator type
///
/// pi: u16, page index, start from 0
///
/// pn: u16, page size,
///
pub async fn select(pi: u16, pn: u16) -> Result<Vec<Indicator>> {
    let q_str = r#"SELECT * FROM indicator ORDER BY id LIMIT $limit START $start"#;

    let start = pi * pn;

    // Fetch kline data within the specified date range using bind variables
    let mut query = FUDB.query(q_str);

    query = query.bind(("limit", pn)).bind(("start", start));

    // println!("query={:?}", query);

    let mut response = query.await?;

    // println!("\nresponse= {:?}\n", response);

    let values: Vec<Indicator> = response.take(0)?;

    Ok(values)
}

#[cfg(test)]
mod test {
    use chrono::Utc;

    use crate::db;
    use crate::db::FUDB;
    use crate::model::indicators::Indicator;
    use crate::model::indicators::INDICATOR_GROUP_KEYS;
    use crate::model::kline::Klt;
    use crate::model::kline::KLINE_COMMON_FIELDS;

    #[tokio::test]
    async fn test_upsert_indicators() {
        let _ = db::init().await.unwrap();

        for gk in INDICATOR_GROUP_KEYS.iter() {
            let indicator = Indicator {
                id: None,
                gk: gk.clone(),
                name: Some(format!("name_{:?}", gk)),
                desc: Some(format!("desc_{:?}", gk)),
                prompt: Some(format!("prompt_{:?}", gk)),
            };

            let res = db::indicators::upsert(&indicator).await;
            println!("res {:?}", res);
        }
    }

    #[tokio::test]
    async fn test_select_indicators() {
        let _ = db::init().await.unwrap();

        let result = db::indicators::select(0, 10).await;

        println!("result= {:?}\n", result);
        assert_eq!(result.is_ok(), true);

        if let Ok(values) = &result {
            for (index, value) in values.iter().enumerate() {
                println!("[{:02}]= {:?} ", index, value);
            }
        }
    }

    #[tokio::test]
    async fn test_compute_n_update_all_indicators() {
        let _ = db::init().await.unwrap();

        let klt_vec = vec![
            // Klt::M005,
            // Klt::M015,
            // Klt::M030,
            // Klt::M060,
            Klt::DAY
            // Klt::WEEK,
            // Klt::MONTH,
        ];

        let mut securities = Vec::new();
        if false {
            securities = db::security::select(&None, None, None, None, 0, 1000).await.unwrap();
        } else {
            let ss = db::security::find("SH.KZZ.110047").await.unwrap();
            securities.push(ss);
        }
        let start = Utc::now();

        for security in &securities {
            for klt in &klt_vec {
                let sec_id = &security.id.clone().unwrap().id.to_raw();
                let klines = db::kline
                    ::select(&sec_id, None, Some(klt), Some("klts ASC"), 0, 10000).await
                    .unwrap();
                if klines.is_empty() {
                    eprintln!("no kline data for {} {}", sec_id, klt);
                    continue;
                }

                let _result = db::indicators::compute_n_update_all_indicators(&klines).await;
                if _result.is_err() {
                    eprintln!("compute_n_update_all_indicators error: {:?}", _result);
                }
            }
        }

        let end = Utc::now();
        println!(
            "\n(test_compute_n_update_all_indicators) Spent time={:?} for securities.len={}\n",
            end - start,
            securities.len()
        );

        let result = db::kline::select(
            "SH.KZZ.110047",
            None,
            Some(&Klt::DAY),
            Some("klts DESC"),
            0,
            3
        ).await;
        if let Ok(klines) = &result {
            for (index, kline) in klines.iter().enumerate() {
                if index > 3 {
                    break;
                }
                // println!(
                //     "[{:02}], close:{:.2}=>adx:{:?}",
                //     index, kline.close, kline.adx,
                // );
            }
        }
    }
    #[tokio::test]
    async fn test_update_klines_indicators_value() {
        let _ = db::init().await.unwrap();

        let klt_vec = vec![
            // Klt::M005,
            // Klt::M015,
            // Klt::M030,
            // Klt::M060,
            Klt::DAY
            // Klt::WEEK,
            // Klt::MONTH,
        ];

        // clean indicators result first
        let _response = FUDB.query(
            r#"UPDATE kline SET 
                    adx=NONE, aroon=NONE, aso=NONE, boll=NONE, cci=NONE,  cko=NONE,
                    cks=NONE, cmf=NONE,   cmo=NONE, cpc=NONE,  dcc=NONE,  dpo=NONE,
                    efi=NONE, eom=NONE,   evl=NONE, ftf=NONE,  hma=NONE,  ikc=NONE, 
                    kama=NONE,kdj=NONE,   knc=NONE,  kst=NONE, kvo=NONE, macd=NONE,  
                    mfi=NONE, mti=NONE,   pcs=NONE,  prs=NONE, rsi=NONE, rvi=NONE,   
                    sar=NONE, sei=NONE,   tdsi=NONE, trix=NONE,trsi=NONE 
                    RETURN NONE
                "#
        ).await.unwrap();

        // TODO: 9501.78s too slow, test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 207 filtered out; finished in 9501.78s

        let mut securities = Vec::new();
        if false {
            securities = db::security::select(&None, None, None, None, 0, 1000).await.unwrap();
        } else {
            let ss = db::security::find("SH.KZZ.110047").await.unwrap();
            securities.push(ss);
        }
        let start = Utc::now();

        for security in &securities {
            for klt in &klt_vec {
                let sec_id = &security.id.clone().unwrap().id.to_raw();
                let klines = db::kline
                    ::select(&sec_id, None, Some(klt), Some("klts ASC"), 0, 10000).await
                    .unwrap();
                if klines.is_empty() {
                    continue;
                }
                let _result = db::indicators::adx::update_adx(&klines, None).await;
                // let _result = db::indicators::aroon::update_aroon(&klines, None).await;
                // let _result = db::indicators::aso::update_aso(&klines, None).await;
                // let _result = db::indicators::boll::update_boll(&klines, None).await;
                // let _result = db::indicators::cci::update_cci(&klines, None).await;
                // let _result = db::indicators::cko::update_cko(&klines, None).await;
                // let _result = db::indicators::cks::update_cks(&klines, None).await;
                // let _result = db::indicators::cmf::update_cmf(&klines, None).await;
                // let _result = db::indicators::cmo::update_cmo(&klines, None).await;
                // let _result = db::indicators::cpc::update_cpc(&klines, None).await;
                // let _result = db::indicators::dcc::update_dcc(&klines, None).await;
                // let _result = db::indicators::dpo::update_dpo(&klines, None).await;
                // let _result = db::indicators::efi::update_efi(&klines, None).await;
                // let _result = db::indicators::eom::update_eom(&klines, None).await;
                // let _result = db::indicators::evl::update_evl(&klines, None).await;
                // let _result = db::indicators::ftf::update_ftf(&klines, None).await;
                // let _result = db::indicators::hma::update_hma(&klines, None).await;
                // let _result = db::indicators::ikc::update_ikc(&klines, None).await;
                // let _result = db::indicators::kama::update_kama(&klines, None).await;
                // let _result = db::indicators::kdj::update_kdj(&klines, None).await;
                // let _result = db::indicators::knc::update_knc(&klines, None).await;
                // let _result = db::indicators::kst::update_kst(&klines, None).await;
                // let _result = db::indicators::kvo::update_kvo(&klines, None).await;
                // let _result = db::indicators::macd::update_macd(&klines, None).await;
                // let _result = db::indicators::mfi::update_mfi(&klines, None).await;
                // let _result = db::indicators::mti::update_mti(&klines, None).await;
                // let _result = db::indicators::pcs::update_pcs(&klines, None).await;
                // let _result = db::indicators::prs::update_prs(&klines, None).await;
                // let _result = db::indicators::rsi::update_rsi(&klines, None).await;
                // let _result = db::indicators::rvi::update_rvi(&klines, None).await;
                // let _result = db::indicators::sar::update_sar(&klines, None).await;
                // let _result = db::indicators::sei::update_sei(&klines, None).await;
                // let _result = db::indicators::tdsi::update_tdsi(&klines, None).await;
                // let _result = db::indicators::trix::update_trix(&klines, None).await;
                // let _result = db::indicators::trsi::update_trsi(&klines, None).await;
                // println!("{:?}", _result);
                // assert_eq!(_result.is_ok(), true);
            }
        }

        let end = Utc::now();
        println!(
            "\n(test_update_klines_indicators_value) Spent time={:?} for securities.len={}\n",
            end - start,
            securities.len()
        );
        let result = db::kline::select(
            "SH.KZZ.110047",
            None,
            Some(&Klt::DAY),
            Some("klts DESC"),
            0,
            3
        ).await;

        if let Ok(klines) = &result {
            for (index, kline) in klines.iter().enumerate() {
                if index > 3 {
                    break;
                }
                // println!(
                //     "[{:02}], close:{:.2}=>adx:{:?}",
                //     index, kline.close, kline.adx,
                // );
            }
        }

        // (test_compute_n_update_all_indicators) Spent time=TimeDelta { secs: 3, nanos: 96216000 } for securities.len=1

        // (kline_of::select) @2024-06-24T04:11:24.338191Z spent time = TimeDelta { secs: 2, nanos: 629372000 } for klines.len=3

        // [00], close:113.50=>adx:Some(ADX { signal0: Some(IndicatorActionWrap { buy: 0, sell: 255 }), signal1: Some(IndicatorActionWrap { buy: 0, sell: 0 }), adx: 0.3412891216334663, di_plus: 0.16791278897319023, di_minus: 0.16816238464635952 })
        // [01], close:113.07=>adx:Some(ADX { signal0: Some(IndicatorActionWrap { buy: 255, sell: 0 }), signal1: Some(IndicatorActionWrap { buy: 7, sell: 0 }), adx: 0.36748500190486666, di_plus: 0.18245516456039748, di_minus: 0.1531591575626386 })
        // [02], close:114.20=>adx:Some(ADX { signal0: Some(IndicatorActionWrap { buy: 255, sell: 0 }), signal1: Some(IndicatorActionWrap { buy: 20, sell: 0 }), adx: 0.3890384102274049, di_plus: 0.20309850089845816, di_minus: 0.12417792881554002 })

        // successes:
        //     db::indicators::test::test_compute_n_update_all_indicators

        // test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 214 filtered out; finished in 29.52s
        // (test_update_klines_indicators_value) Spent time=TimeDelta { secs: 4, nanos: 189906000 } for securities.len=1

        // (kline_of::select) @2024-06-24T04:30:01.914147Z spent time = TimeDelta { secs: 3, nanos: 142726000 } for klines.len=3

        // [00], close:113.50=>adx:Some(ADX { signal0: Some(IndicatorActionWrap { buy: 0, sell: 255 }), signal1: Some(IndicatorActionWrap { buy: 0, sell: 0 }), adx: 0.3412891216334663, di_plus: 0.16791278897319023, di_minus: 0.16816238464635952 })
        // [01], close:113.07=>adx:Some(ADX { signal0: Some(IndicatorActionWrap { buy: 255, sell: 0 }), signal1: Some(IndicatorActionWrap { buy: 7, sell: 0 }), adx: 0.36748500190486666, di_plus: 0.18245516456039748, di_minus: 0.1531591575626386 })
        // [02], close:114.20=>adx:Some(ADX { signal0: Some(IndicatorActionWrap { buy: 255, sell: 0 }), signal1: Some(IndicatorActionWrap { buy: 20, sell: 0 }), adx: 0.3890384102274049, di_plus: 0.20309850089845816, di_minus: 0.12417792881554002 })

        // successes:
        //     db::indicators::test::test_update_klines_indicators_value

        // test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 214 filtered out; finished in 34.68s
    }
}
